﻿#include "basic_typedef.h"
#include "FilesReader.hpp"
#include "TrianglesCreator.hpp"
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <CGAL/intersections.h>
#include <boost/timer.hpp>

using namespace std;

typedef Polygon::Vertex_const_iterator Vit;
typedef Polygon::Edge_const_iterator Edge_it;

void parse_args(int argc, char* argv[], string& polygon_file_name, string& camera_file_name);

void print_point ( Point const& p )
{
  std::cout << "(" << p.x() << "," << p.y() << ")" ;
}

void print_polygon ( Polygon const& poly )
{
  std::cout << "Polygon with " << poly.size() << " vertices" << std::endl ;
  
  for( Polygon::Vertex_const_iterator vi = poly.vertices_begin() ; vi != poly.vertices_end() ; ++ vi )
  {
    print_point(*vi); std::cout << std::endl ;
  }  
}


void print_polygons ( vector<Polygon> const& polies )
{
  std::cout << "Polygon list with " << polies.size() << " polygons" << std::endl ;
  
  for(vector<Polygon>::const_iterator pi = polies.begin() ;
	  pi != polies.end();
	  ++pi)
  {
    print_polygon(*pi);
  }
}
	
void print_uncovered_point ( Polygon_with_holes const& polywh )
{
	Polygon::Vertex_const_iterator vi = polywh.outer_boundary().vertices_begin();
	cout << "The cameras do not cover the point ";
	print_point(*vi);
	cout << endl;
}

void print_polygon_with_holes ( Polygon_with_holes const& polywh )
{
  std::cout << "Polygon_with_holes having " << polywh.number_of_holes() << " holes" << std::endl ;
  
  print_polygon(polywh.outer_boundary());
  
  for( Polygon_with_holes::Hole_const_iterator hi = polywh.holes_begin() ; hi != polywh.holes_end() ; ++ hi )
  {
	  cout << "H" << endl;
    print_polygon(*hi);
  }
}

int main(int argc, char* argv[])
{
    try
    {
        string polygon_file_name = "polygon.txt";
        string camera_file_name = "camera.txt";
        parse_args(argc, argv, polygon_file_name, camera_file_name);

        Polygon polygon = FileReader::create_polygon_from_file(polygon_file_name);

        vector<Point> cameras_list = FileReader::create_cameras_list(camera_file_name);
		
		boost::timer timer;

        int guard_idx = 1;
		Polygon_set polygon_set;
		bool is_first = true;

        for(std::vector<Point>::iterator guards_it = cameras_list.begin();
			guards_it != cameras_list.end();
			++guards_it, ++guard_idx)
        {
            vector<Polygon> covered_triangles = TrianglesCreator::get_covered_triangles(polygon, *guards_it);

			for (vector<Polygon>::iterator tirangles_it = covered_triangles.begin();
				tirangles_it != covered_triangles.end();
				tirangles_it++)
			{
				if (is_first)
				{
					polygon_set.insert(*tirangles_it);
					is_first = false;
				}
				else
				{
					polygon_set.join(*tirangles_it);
				}
			}
        }

		std::list<Polygon_with_holes> res;
		std::list<Polygon_with_holes>::const_iterator it;
		polygon_set.polygons_with_holes (std::back_inserter (res));
		polygon_set.symmetric_difference(polygon);
		
		double secs = timer.elapsed();
		cout << "Execution time: " << secs << endl;

		if (polygon_set.number_of_polygons_with_holes() == 0)
		{
			cout << "The cameras cover the polygon!" << endl;
		}
		else
		{
			std::list<Polygon_with_holes> res2;
			std::list<Polygon_with_holes>::const_iterator it2;
			polygon_set.polygons_with_holes (std::back_inserter (res2));
			it2 = res2.begin();
			print_uncovered_point(*it2);
		}
    }
    catch(const Exception& exp)
    {
        cout << "Caught exception: " << exp.get_message() << endl;
        return 1;
    }

    return 0;
}

void parse_args(int argc, char* argv[], string& polygon_file_name, string& camera_file_name)
{
    if (argc == 1)
    {
        return;
    }
    if (argc == 2)
    {
        polygon_file_name = argv[1];
    }
    else if (argc == 3)
    {
        polygon_file_name = argv[1];
        camera_file_name = argv[2];
    }
    else
    {
        cout << "Usage: do_cover.exe polygon.txt camera.txt" << endl;
        throw Exception("Bad usage");
    }
}
